package TestSuite;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;

//This class handles the logging of data connected to fault handling by utilizing aspects and generates a log file 
public class Logger {

	//These variables are used for statistics of faults correcte
	//int oldValue = 0;			//used to hold the value before correction for logging 
	//char[] oldString;
	long startTime;
	//long currentTime;
	int opcodeFaults = 0;
	int ifcodeFaults = 0;
	int aritFaults = 0;
	int valueFaults = 0;
	int stringFaults = 0;
	int keyFaults = 0;
	int totalFaults = 0;
	File fileIn;
	
	//Constructor that instantiate the things needed to make a log file with date and time stamp
	public Logger()
	{
		Calendar d = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("dd-M-HH-mm-ss");
		fileIn = new File("bosVMLog.txt");
		startTime = System.currentTimeMillis();
		PrintWriter out = null;
		
		try 
		{
			out = new PrintWriter(new BufferedWriter(new FileWriter(fileIn, true)));
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		
		try
		{
			out.println(" ");
			out.println("Created " + sdf.format(d.getTime()));
			out.println(" ");
			
		}
		finally 
		{
			if(out != null)
			{
				out.close();
			}
		}
	}
	
	public void addRuntime()
	{
		int runtime = 0;
		File fileInput = new File("log1-baseXint.txt");
		BufferedReader br = null;
		try{
			br = new BufferedReader(new FileReader(fileInput));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		try {
			String[] s = br.readLine().split(",");
			for(int i = 0; i < s.length; i ++)
			{
				int n = Integer.parseInt(s[i]);
				runtime = runtime + n;
			}
			runtime = runtime / s.length;
			System.out.println("The runtime is: " + runtime);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public void addLog()	
	{
		File fileInput = new File("bosVMLog0.txt");
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(fileInput));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String s = "";
		try {
			s = br.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		while(s != null)
		{
			
			if(s.contains("Opcode faults corrected:"))
			{
				int temp = Integer.parseInt(s.substring(s.length()-1));
				
				opcodeFaults = opcodeFaults + temp;
			}
			else if(s.contains("Value faults corrected"))
			{
				int temp = Integer.parseInt(s.substring(23, s.length()));
				
				valueFaults = valueFaults + temp;
			}
			else if(s.contains("AritOpcode faults corrected:"))
			{
				int temp = Integer.parseInt(s.substring(29, s.length()));
				
				aritFaults = aritFaults + temp;
			}
			else if(s.contains("IfOpcode faults corrected:"))
			{
				int temp = Integer.parseInt(s.substring(27, s.length()));
				
				ifcodeFaults = ifcodeFaults + temp;
			}
			else if(s.contains("String faults corrected:"))
			{
				int temp = Integer.parseInt(s.substring(25, s.length()));
				
				stringFaults = stringFaults + temp;
			}
			else if(s.contains("Map key faults corrected:"))
			{
				int temp = Integer.parseInt(s.substring(26, s.length()));
				
				keyFaults = keyFaults + temp;
			}
			else if(s.contains("Total faults corrected:"))
			{
				int temp = Integer.parseInt(s.substring(24, s.length()));
				
				totalFaults = totalFaults + temp;
				System.out.println(totalFaults);
			}
			
			try {
				s = br.readLine();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(" ");
		System.out.println("Opcode faults corrected: " + opcodeFaults);
		System.out.println("Value faults corrected " + valueFaults);
		System.out.println("AritOpcode faults corrected: " + aritFaults);
		System.out.println("IfOpcode faults corrected: " + ifcodeFaults);
		System.out.println("String faults corrected: " + stringFaults);
		System.out.println("Map key faults corrected: " + keyFaults);
		System.out.println(" ");
		System.out.println("Total faults corrected: " + totalFaults);
	}
	
	//This method is run before its pointcut to save the old value for use in log
	/*public void getOldValue(Object o, String s, Object[] p)
	{
		MethodFrame m;
		if(s.contains("handleOpcodeFault"))
		{
			m = (MethodFrame)o;
			oldValue = (int)m.getMethod().instructionAt(m.getpc())[0];
		}
		else if(s.contains("handleAritcodeFault") || s.contains("handleIfcodeFault"))
		{
			m = (MethodFrame)o;
			oldValue = (int) m.getMethod().instructionAt(m.getpc())[1];
		}
		else if(s.contains("handleValueFault"))
		{
			m = (MethodFrame)o;
			oldValue = (int)p[0];
		}
		else if(s.contains("correctBitFlip"))
		{
			System.out.println("logggggggggggggger " + p[1].toString());
			oldString = (char[]) p[1];
		}
	}*/
	
	
	//Wraps up the log with statistics and is run after the execution of the VM is done
	public void generateLogEnd()
	{
		PrintWriter out = null;
		
		try 
		{
			out = new PrintWriter(new BufferedWriter(new FileWriter(fileIn, true)));
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		
		try
		{
			out.println(" ");
			out.println("Opcode faults corrected: " + opcodeFaults);
			out.println("Value faults corrected " + valueFaults);
			out.println("AritOpcode faults corrected: " + aritFaults);
			out.println("IfOpcode faults corrected: " + ifcodeFaults);
			out.println("String faults corrected: " + stringFaults);
			out.println("Map key faults corrected: " + keyFaults);
			out.println(" ");
			out.println("Total faults corrected: " + (opcodeFaults + valueFaults + aritFaults + ifcodeFaults + stringFaults + keyFaults));
			out.println("Total runtime: " + (System.currentTimeMillis() - startTime));
		}
		finally 
		{
			if(out != null)
			{
				out.close();
			}
		}
	}
	
	//Called after every fault handler method is run and will generate an entry in the log depending on the type of fault
	public void generateLogEntry(String s)
	{ 
		PrintWriter out = null;
		
		try 
		{
			
			try
			{
				out = new PrintWriter(new BufferedWriter(new FileWriter(fileIn, true)));
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
			out.print((System.currentTimeMillis() - startTime) + " ");
			//in case of opcode faults
			if(s.contains("handleOpcodeFault"))
			{
				out.println("Intruction-Opcode fault detected and corrected");
				++ opcodeFaults;
			}
			//in case of arit code faults
			else if(s.contains("handleAritcodeFault"))
			{
				out.println("Arit-Opcode fault detected and corrected");
				++ aritFaults;
			}
			//in case of if code faults
			else if(s.contains("handleIfcodeFault"))
			{
				out.println("If-Opcode fault detected and corrected");
				++ ifcodeFaults;
			}
			else if(s.contains("handleValueFault"))
			{
				out.println("Value fault detected and corrected");
				++ valueFaults;
			}
			else if(s.contains("correctBitFlip"))
			{
				out.println("String fault detected and corrected");
				++ stringFaults;
			}
			else if(s.contains("mapKeyErrorCorrection") || s.contains("methodsMapKeyErrorCorrection") || s.contains("mapKeyErrorCorrection"))
			{
				out.println("Map key fault detected and corrected");
				++ keyFaults;
			}
			
		}
		finally
		{
			if(out != null)
			{
				out.close();
			}
		}
	}
	
	//Alternative generateLogEntry for value faults 
	//takes an integer as argument which is the new value after correction has happened
	/*public void generateLogEntry(String s, Object o, Integer i)
	{ 
		PrintWriter out = null;
		MethodFrame m = (MethodFrame)o;
		
		try 
		{
			try 
			{
				out = new PrintWriter(new BufferedWriter(new FileWriter(fileIn, true)));
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
			//in case of value faults
			if(s.contains("handleValueFault"))
			{
				out.println("Value "  + oldValue + " was not equal to copy and corrected to " + i);
				++ valueFaults;
			}
		}
		finally
		{
			if(out != null)
			{
				out.close();
			}
		}
	}
	
	public void generateLogEntry(String s, char[] c)
	{ 
		PrintWriter out = null;
		
		try 
		{
			try 
			{
				out = new PrintWriter(new BufferedWriter(new FileWriter(fileIn, true)));
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
			//in case of value faults
			if(s.contains("correctBitFlip"))
			{
				out.print("Identifier ");
				out.print(stringEnc.toASCII(oldString)); 
				out.print(" was not recognized and corrected to "); 
				out.println(stringEnc.toASCII(c));
				++ stringFaults;
			}
		}
		finally
		{
			if(out != null)
			{
				out.close();
			}
		}
	}*/
	
	public static void main(String [ ] args)
	{
	    Logger logger = new Logger();
	    logger.addLog();
	    //logger.addRuntime();
	}
}
